文章已同步發表至 Medium
將 NetTopologySuite.IO.Esri
加入我們的專案之後,就可以開始對我們的 Shapefile 進行操作了。這裡使用政府開放平臺所提供的資料作為範例,也是我們之後實作會使用到的其中一個檔案。
using NetTopologySuite.IO.Esri;
foreach (var feature in Shapefile.ReadAllFeatures(@"shapefile path"))
{
foreach (var attrName in feature.Attributes.GetNames())
{
Console.WriteLine($"{attrName,10}: {feature.Attributes[attrName]}");
}
// Console.WriteLine($" SHAPE: {feature.Geometry.AsText()}");
Console.WriteLine($" SRID: {feature.Geometry.SRID}");
Console.WriteLine();
}
根據 GitHub 上的寫法,只要簡單的這幾行,馬上就能讀取 Shapefile 了!執行後的結果如下:
從讀取後的結果可以看到,之前讓我們在 GDAL 中痛苦不已的中文,在 NetTopologySuite
上可以好好的正常顯示!(痛哭流涕)
另外也可以看到,NetTopologySuite
在寫法上相對來說更為簡潔,一開始可以選擇直接讀取 Feature
就好,再透過欄位名稱從 Atrributes
取得 Field
的值,不像 GDAL 還需要從 Layer
先取得 Layer
的數量跑回圈,接著從 Layer
拿 layer.GetNextFeature()
才能開始讀資料,可讀性比起 GDAL 高出許多。
using System.Text;
using NetTopologySuite.Features;
using NetTopologySuite.IO;
using NetTopologySuite.IO.Esri;
var features = new List<Feature>();
var wktReader = new WKTReader();
var fcuGeometry = wktReader.Read(
"POLYGON((214094.18733422138 2675204.397772933,214613.04806256315 2675203.096234374,214612.0331897791 2674795.5200602347,214093.15758024747 2674796.8214499434,214094.18733422138 2675204.397772933))");
var fcuAttributes = new AttributesTable();
fcuAttributes.Add("日期", DateTime.Today);
fcuAttributes.Add("地點", "逢甲大學");
var fcuFeature = new Feature(fcuGeometry, fcuAttributes);
features.Add(fcuFeature);
var nightMarketGeometry = wktReader.Read(
"POLYGON((213945.3342767608 2674876.347737663,214097.93845940504 2674873.793433358,214099.4943339883 2674626.6362772766,214474.48457545802 2674625.694102451,214511.39058478415 2674562.7289472898,214223.11502519806 2674368.326804782,213983.77470059253 2674559.719947559,213945.3342767608 2674876.347737663))");
var nightMarketAttributes = new AttributesTable();
nightMarketAttributes.Add("日期", DateTime.Today);
nightMarketAttributes.Add("地點", "逢甲夜市");
var nightMarketFeature = new Feature(nightMarketGeometry, nightMarketAttributes);
features.Add(nightMarketFeature);
Shapefile.WriteAllFeatures(features, @"files\create.shp", Encoding.UTF8);
根據 GitHub 上的範例,一樣可以簡單的利用使用 Shapefile.WriteAllFeatures()
來建立。不過,範例上建立的是 MultiLine
,把他修改成 Polygon
之後,執行時遇到了一個錯誤:
一開始看到錯誤原因的時候真的覺得很茫然 ? 我很確定我的 WKT 是 Polygon 沒有錯,為甚麼 Exception 會告訴我我想把 Polygon 轉換成 Multi Polygon 呢 ?
於是開啟 debbug mode,順著程式碼一行一行往下找,終於在 Shapefile.cs
中找到一點線索。在最後要使用 Writer 寫入的時候,他所建立的 Writer 泛型所吃的類別竟然只有 Multi Polygon
的選項 ?
也就是說,就算我的 Geometry 型別是 Polygon
,但 Writer 依舊會以 MultiPolygon
建立,但因為型別不同,所以在使用 Writer 前他會一直想把我的型別轉換成 MultiPolygon
,才會一直噴出 Exception。
但原始碼裡,Writer 只有針對 MultiPolygon
去進行寫入的方法,也就等於所有 Polygon 相關的類別:Polygon
、PolygonM
、PolygonZ
、PolygonZM
都會使用 Multi Polygon Writer 去建立。